use anyhow::Result;
// use dotenvy::dotenv;
// use helpers::Bot;
// use teloxide::{dispatching::UpdateFilterExt, prelude::*, types::Update};
// use helpers::Db;
use log::warn;
use std::ops::Deref;

use db::Db;
mod handlers;
mod helpers;
#[forbid(clippy::large_futures)]
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() {
    // Get values from .env file
    // dotenv().ok();
    run_bot().await;
}

use matrix_sdk::{
    config::SyncSettings,
    event_handler::Ctx,
    matrix_auth::{MatrixSession, MatrixSessionTokens},
    room::Room,
    ruma::events::room::message::{
        MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent,
    },
    Client, SessionMeta,
};

async fn messages_handler(
    event: OriginalSyncRoomMessageEvent,
    room: Room,
    client: Client,
    db: Ctx<Db>,
) -> Result<()> {
    // if let room::Room(room) = room {
    if event.sender != *client.user_id().unwrap() {
        match event.content.msgtype.clone() {
            MessageType::Text(message) => {
                let text = {
                    if let Some(formatted_message) = message.formatted {
                        formatted_message.body
                    } else {
                        message.body
                    }
                };
                if text.contains("!party") {
                    let content =
                        RoomMessageEventContent::text_plain("🎉🎊🥳 let's PARTY!! 🥳🎊🎉");

                    println!("sending");

                    // send our message to the room we found the "!party" command in
                    // the last parameter is an optional transaction id which we don't
                    // care about.
                    room.send(content).await?;

                    println!("message sent");
                    //   Ok(())
                } else if text.contains("!archive") {
                    handlers::archive(event, text, room, client, db.deref().clone()).await?;
                } else if text.contains("!unarchive") {
                    handlers::unarchive(event, text, room, client, db.deref().clone()).await?;
                } else if text.contains("!random") {
                    handlers::random(event, text, room, client, db.deref().clone()).await?;
                } else if text.contains("!delete") {
                    handlers::delete(event, text, room, client, db.deref().clone()).await?;
                } else if text.contains("!favorite") {
                    handlers::favorite(event, text, room, client, db.deref().clone()).await?;
                } else if text.contains("!unfavorite") {
                    handlers::unfavorite(event, text, room, client, db.deref().clone()).await?;
                } else if text.contains("!count_unread_time") {
                    handlers::count_unread_time(event, text, room, client, db.deref().clone())
                        .await?;
                } else if text.contains("!count_unread") {
                    handlers::count_unread_posts(event, text, room, client, db.deref().clone())
                        .await?;
                } else if text.contains("!show_real_url") {
                    handlers::show_real_url(event, text, room, client, db.deref().clone()).await?;
                } else if text.contains("!show_alternative_url") {
                    handlers::show_alternative_url(event, text, room, client, db.deref().clone())
                        .await?;
                } else {
                    handlers::add(event, text, room, client, db.deref().clone()).await?;
                    //Ok(())
                }
            }
            _ => return Ok(()),
        };
    }
    // }
    Ok(())
}

async fn run_bot() {
    pretty_env_logger::formatted_builder()
        .filter(
            Some(&env!("CARGO_CRATE_NAME").replace('-', "_")),
            log::LevelFilter::Info,
        )
        .filter(Some("matrix"), log::LevelFilter::Info)
        //.target(pretty_env_logger::env_logger::Target::Stdout)
        .init();
    let postgres_url = std::env::var("POSTGRES_URL").unwrap();
    let db = db::Db::connect(&postgres_url).await.unwrap();
    log::info!("Starting readlaterbot...");
    // let bot_name = std::env::var("BOT_NAME").unwrap();
    // let user_id = user_id!(bot_name);
    let homeserver_url = std::env::var("MATRIX_HOMESERVER_URL").unwrap();
    let username = std::env::var("MATRIX_USERNAME").unwrap();
    let user_id = std::env::var("MATRIX_USER_ID").unwrap();
    let password = std::env::var("MATRIX_PASSWORD").unwrap();
    // login_and_sync(homeserver_url, &username, &password).await?;
    let mut client_builder = Client::builder().homeserver_url(homeserver_url);
    // let home = dirs::home_dir()
    //     .expect("no home directory found")
    //     .join("readlater_bot");
    // let device_id = std::env::var("MATRIX_DEVICE_ID").ok();
    // let access_token = std::env::var("MATRIX_ACCESS_TOKEN").ok();
    let home = "/readlaterbot/readlater_bot";
    {};
    dbg!(home);
    client_builder = client_builder.sqlite_store(home, None);
    let client = client_builder.build().await.unwrap();
    let config = db.get_matrix_config().await.unwrap();
    if let Some(config) = config {
        if let Some(device_id) = config.device_id {
            if let Some(access_token) = config.access_token {
                let session = MatrixSession {
                    meta: SessionMeta {
                        user_id: user_id.try_into().unwrap(),
                        device_id: device_id.into(),
                    },
                    tokens: MatrixSessionTokens {
                        access_token,
                        refresh_token: None,
                    }, // access_token,
                       // device_id: ,
                       // user_id: user_id.try_into().unwrap(),
                       // refresh_token: None,
                };
                client.restore_session(session).await.unwrap();
                //    warn!("restored session: {:#?}", session.device_id);
            }
        }
    } else {
        let session: MatrixSession = (&client
            .matrix_auth()
            .login_username(&username, &password)
            .initial_device_display_name("readlaterbot")
            .await
            .unwrap())
            .into();
        warn!("New Session: {:#?}", session);
        db.save_matrix_config(
            &session.tokens.access_token,
            session.meta.device_id.as_str(),
        )
        .await
        .unwrap();
    }
    // info!("{:#?}", client.encryption().cross_signing_status().await);
    // client.encryption().bootstrap_cross_signing(auth_data)
    let response = client.sync_once(SyncSettings::default()).await.unwrap();
    let settings = SyncSettings::default().token(response.next_batch);
    client.add_event_handler_context(db);
    client.add_event_handler(messages_handler);
    // client.add_event_handler(handlers::original_room_sync);
    // client.add_event_handler(handlers::original_room_start_sync);
    // client.add_event_handler(handlers::to_device_sync);
    // client.add_event_handler(handlers::to_device_start_sync);
    client.add_event_handler(handlers::join);
    client.sync(settings).await.unwrap();
}
